

package com.love.cloud.common.core.config;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Locale;
import java.util.TimeZone;

/**
 * JacksonConfig
 * json转换规则初始化
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JacksonConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public Jackson2ObjectMapperBuilderCustomizer customizer() {
		return builder -> {
			builder.locale(Locale.CHINA);
			builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
			builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
			builder.serializerByType(Long.class, ToStringSerializer.instance);
			JavaTimeModule javaTimeModule = new JavaTimeModule();
			javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
			javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
			builder.modules(javaTimeModule);
		};
	}

	/**
	 * description:LocalDateTime转换器，用于转换RequestParam和PathVariable参数
	 * 接收毫秒级时间戳字符串——>LocalDateTime
	 */
	@Bean
	public Converter<String, LocalDateTime> localDateTimeConverter() {
		return new Converter<String, LocalDateTime>() {
			@Override
			public LocalDateTime convert(String source) {
				//毫秒级时间戳转LocalDateTime
				return LocalDateTimeUtil.of(Long.parseLong(source), ZoneOffset.of("+8"));
			}
		};
	}

	public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
		@Override
		public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
			gen.writeNumber(value.toInstant(ZoneOffset.of("+8")).toEpochMilli());
		}
	}

	public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
		@Override
		public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext) throws IOException {
			Instant instant = Instant.ofEpochMilli(p.getLongValue());
			return LocalDateTime.ofInstant(instant, ZoneOffset.of("+8"));
		}
	}

}
